<?php
/**
 * crcl/base
 *
 * Copyright 2013 CRCL - André Sabosch - info@crcl.de
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace crcl\base\template\instructions;

interface IConcrete
{
  /**
   * Compiles instruction
   * You can fetch results with @see getOutput
   */
  public function execute();

  /**
   * Verifies instruction
   * Note: use property aAllowedAttributes in container
   */
  public function verify();

  /**
   * Sets attributes
   *
   * @param $aAttributes  array
   */
  public function setAttributes($aAttributes);

  /**
   * Returns output, defaults to empty string
   *
   * @return string
   */
  public function getOutput();

  public function getTriggeredOutput();

  public function getScope();
}

abstract class Base implements IConcrete
{
  public function setAttributes($aAttributes)
  {
    $this->aAttributes = $aAttributes;
  }

  public function getOutput()
  {
    return $this->sOutput;
  }

  public function verify()
  {
    foreach ($this->aAttributes as $sAttribute => $sValue)
    {
      $iPos = \strpos($sAttribute, ':');
      if ($iPos !== \FALSE)
      {
        $sAttribute = \substr($sAttribute, 0, $iPos);
      }

      if (!\in_array($sAttribute, $this->aAllowedAttributes))
      {
        throw new Exception('Invalid attribute combination',
          Exception::ERROR_INVALIDATTRIBUTECOMBINATION,
          array('attribute' => $sAttribute, 'mode' => get_called_class()));
      }
    }

    return \TRUE;
  }

  public function getTriggeredOutput()
  {
    return $this->sOutputTriggered;
  }

  public function getTriggeredAttributes()
  {
    return $this->aAttributesTriggered;
  }

  public function getScope()
  {
    return $this->sScope;
  }

  public static function startHeredoc()
  {
    return '$sContent .= <<<BASE' . "\n";
  }

  public static function endHeredoc()
  {
    return "\n" . 'BASE;' . "\n";
  }

  public static function startContent()
  {
    return '$sContent .= ';
  }
  /** PROTECTED ***********************************************************************************/

  protected $sOutput = '';
  protected $sOutputTriggered = '';
  protected $aAttributesTriggered = array();
  protected $aAttributes = array();
  protected $sScope = \crcl\base\template\Instruction::SCOPE_CURRENT;

  protected function getAttribute($sAttribute)
  {
    if ($this->hasAttribute($sAttribute))
    {
      return $this->aAttributes[$sAttribute];
    }
    else
    {
      throw new Exception('Unknown attribute',
        Exception::ERROR_UNKNOWNATTRIBUTE,
        array('attribute' => $sAttribute));
    }
  }

  protected function hasAttribute($sAttribute)
  {
    if (isset($this->aAttributes[$sAttribute]))
    {
      return \TRUE;
    }
    return \FALSE;
  }
}